package com.cloud.handlerWritingOpenfeign;

import lombok.SneakyThrows;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;

import java.util.List;

/**
 * 注入IOC
 */
public class HandWritingRegister implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    private ResourceLoader resourceLoader;

    private Environment environment;

    // EnvironmentAware 可以读取配置文件
    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {

    }

    // ImportBeanDefinitionRegistrar 自定义优先注册bean，否则其他地方引用报错为空
    @SneakyThrows
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        List<FindMapping.PackDetails> mapping = FindMapping.getMapping();
        if (CollectionUtils.isEmpty(mapping)) {
            return;
        }
        for (FindMapping.PackDetails res : mapping) {
            Class<?> aClass = Class.forName(res.getClassName());
            Object o = HandWritingProxy.create(aClass, res);

            // ConstructorArgumentValues 为了使用有参构造函数做bean注入
            // 使用无参构造函数注入动态代理生成的对象报错
            ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
            constructorArgumentValues.addIndexedArgumentValue(0, new FeignInvocationHandler(res, aClass));
            BeanDefinition beanDefinition = new RootBeanDefinition(o.getClass(), constructorArgumentValues, null);
            BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, aClass.getSimpleName(),
                    null);
            //将bean优先注入到ioc
            BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
        }
    }
}
